#include "Renderer.h"
#include <GL/glut.h>
#include "Game.h"
#include "TextureManager.h"
#include "Colors.h"
#include "Dungeon.h"
#include "Util.h"
#include "Keyboard.h"
#include "StringLib.h"
#include "Tile.h"
#include "Ingredient.h"
#include "Misc.h"
#include "Potion.h"
#include "Tool.h"
#include "MeleeWeapon.h"
#include "RangedWeapon.h"
#include "Npc.h"
#include "Player.h"
#include "Door.h"
#include "ItemContainer.h"
#include "Resource.h"
#include "Trap.h"
#include "Level.h"
#include "Wall.h"
#include "Portal.h"
#include "TextLog.h"
#include "ItemStack.h"
#include "Equipment.h"
#include "RecipeManager.h"
#include "Recipe.h"
#include "Corpse.h"
#include "Scroll.h"
#include "Armor.h"
#include "Shield.h"
#include "AvailableTalents.h"
#include "Ammo.h"
#include <vector>

Renderer::Renderer(TextureManager* textureManager) {
	m_textureManager = textureManager;
}

Renderer::~Renderer() {
	delete m_textureManager;
}

void Renderer::renderTexture(unsigned int texture, float x, float y, float width, float height) {
	glBindTexture(GL_TEXTURE_2D, texture);
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glBegin(GL_QUADS);
	glTexCoord2f(0.0f, 0.0f);
	glVertex2f(x, y);
	glTexCoord2f(1.0f, 0.0f);
	glVertex2f(x+width, y);
	glTexCoord2f(1.0f, 1.0f);
	glVertex2f(x+width, y+height);
	glTexCoord2f(0.0f, 1.0f);
	glVertex2f(x, y+height);
	glEnd();
	glDisable(GL_BLEND);
	glDisable(GL_TEXTURE_2D);
}

void Renderer::renderQuad(float x, float y, float width, float height) {
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glBegin(GL_QUADS);
	glVertex2f(x, y);
	glVertex2f(x+width, y);
	glVertex2f(x+width, y+height);
	glVertex2f(x, y+height);
	glEnd();
	glDisable(GL_BLEND);
}

void Renderer::renderOutline(float x, float y, int lineWidth, float width, float height) {
	glLineWidth(lineWidth);
	glBegin(GL_LINES);
	int ciel = int((float(lineWidth))/2.0f+0.5f);
	int floor = lineWidth/2;
	glVertex2f(x, y+floor);
	glVertex2f(x+width, y+floor);
	glVertex2f(x+width-ciel, y);
	glVertex2f(x+width-ciel, y+height);
	glVertex2f(x+width, y+height-ciel);
	glVertex2f(x, y+height-ciel);
	glVertex2f(x+floor, y+height);
	glVertex2f(x+floor, y);
	glEnd();
	glLineWidth(1);
}

void Renderer::render(const Tile& tile, float x, float y) {
	if(tile.isExplored()) {
		renderTexture(m_textureManager->getTileTexture(tile.getLevel()->getDungeon()->getDungeonType(), tile.getTileType(), int(tile.getX()), int(tile.getY())), x, y);
		std::list<Item*>* items = tile.getItems();
		for(std::list<Item*>::const_iterator iter = items->begin(); iter != items->end(); iter++)
			(*iter)->render(x, y);
		if(tile.getObstacle())
			tile.getObstacle()->render(x, y);
		if(tile.getCharacter())
			tile.getCharacter()->render(x, y);
		if(!tile.isVisible()) {
			glColor4fv(FOG_COLOR);
			renderQuad(x, y);
			glColor3fv(DEFAULT_COLOR);
		}
	}
}
void Renderer::render(const Ammo& ammo, float x, float y) {
	renderTexture(m_textureManager->getObjectTexture(TH_AMMO_TYPE, ammo.getType(TH_AMMO_TYPE)), x, y);
}
void Renderer::render(const Armor& armor, float x, float y) {
	renderTexture(m_textureManager->getObjectTexture(TH_ARMOR_TYPE, armor.getType(TH_ARMOR_TYPE)), x, y);
	if(DEBUG) {
		if(armor.getPrefix() != AP_NONE) {
			glColor3fv(DEBUG_PREFIX_COLOR);
			renderQuad(x+1, y+TILE_HEIGHT-4, 3.0f, 3.0f);
		}
		if(armor.getSuffix() != AS_OF_NONE) {
			glColor3fv(DEBUG_SUFFIX_COLOR);
			renderQuad(x+TILE_HEIGHT-4, y+TILE_HEIGHT-4, 3.0f, 3.0f);
		}
		if(armor.isHighQuality()) {
			glColor3fv(DEBUG_HIGH_QUALITY_COLOR);
			renderQuad(x+TILE_WIDTH/2-2, y+TILE_HEIGHT-4, 3.0f, 3.0f);
		}
		glColor3fv(DEFAULT_COLOR);
	}
}
void Renderer::render(const Food& food, float x, float y) {
	renderTexture(m_textureManager->getObjectTexture(TH_FOOD_TYPE, food.getType(TH_FOOD_TYPE)), x, y);
}
void Renderer::render(const Corpse& corpse, float x, float y) {
	renderTexture(m_textureManager->getObjectTexture(TH_NPC_TYPE, corpse.getNpcType()), x, y);
	renderTexture(m_textureManager->getObjectTexture(TH_FOOD_TYPE, FT_CORPSE), x, y);
}
void Renderer::render(const Ingredient& ingredient, float x, float y) {
	renderTexture(m_textureManager->getObjectTexture(TH_INGREDIENT_TYPE, ingredient.getType(TH_INGREDIENT_TYPE)), x, y);
}
void Renderer::render(const Misc& misc, float x, float y) {
	renderTexture(m_textureManager->getObjectTexture(TH_MISC_TYPE, misc.getType(TH_MISC_TYPE)), x, y);
}
void Renderer::render(const Potion& potion, float x, float y) {
	renderTexture(m_textureManager->getObjectTexture(TH_POTION_TYPE, potion.getScrambledType()), x, y);
}
void Renderer::render(const Shield& shield, float x, float y) {
	renderTexture(m_textureManager->getObjectTexture(TH_SHIELD_TYPE, shield.getType(TH_SHIELD_TYPE)), x, y);
	if(DEBUG) {
		if(shield.getPrefix() != SP_NONE) {
			glColor3fv(DEBUG_PREFIX_COLOR);
			renderQuad(x+1, y+TILE_HEIGHT-4, 3.0f, 3.0f);
		}
		if(shield.getSuffix() != SS_OF_NONE) {
			glColor3fv(DEBUG_SUFFIX_COLOR);
			renderQuad(x+TILE_HEIGHT-4, y+TILE_HEIGHT-4, 3.0f, 3.0f);
		}
		if(shield.isHighQuality()) {
			glColor3fv(DEBUG_HIGH_QUALITY_COLOR);
			renderQuad(x+TILE_WIDTH/2-2, y+TILE_HEIGHT-4, 3.0f, 3.0f);
		}
		glColor3fv(DEFAULT_COLOR);
	}
}
void Renderer::render(const Tool& tool, float x, float y) {
	renderTexture(m_textureManager->getObjectTexture(TH_TOOL_TYPE, tool.getType(TH_TOOL_TYPE)), x, y);
	if(DEBUG) {
		if(tool.getPrefix() != TP_NONE) {
			glColor3fv(DEBUG_SUFFIX_COLOR);
			renderQuad(x+1, y+TILE_HEIGHT-4, 3.0f, 3.0f);
		}
		if(tool.getSuffix() != TS_OF_NONE) {
			glColor3fv(DEBUG_SUFFIX_COLOR);
			renderQuad(x+1, y+TILE_HEIGHT-4, 3.0f, 3.0f);
		}
		if(tool.isHighQuality()) {
			glColor3fv(DEBUG_HIGH_QUALITY_COLOR);
			renderQuad(x+TILE_WIDTH/2-2, y+TILE_HEIGHT-4, 3.0f, 3.0f);
		}
		glColor3fv(DEFAULT_COLOR);
	}
}
void Renderer::render(const MeleeWeapon& weapon, float x, float y) {
	renderTexture(m_textureManager->getObjectTexture(TH_MELEE_WEAPON_TYPE, weapon.getType(TH_MELEE_WEAPON_TYPE)), x, y);
	if(DEBUG) {
		if(weapon.getPrefix() != MWP_NONE) {
			glColor3fv(DEBUG_PREFIX_COLOR);
			renderQuad(x+1, y+TILE_HEIGHT-4, 3.0f, 3.0f);
		}
		if(weapon.getSuffix() != MWS_OF_NONE) {
			glColor3fv(DEBUG_SUFFIX_COLOR);
			renderQuad(x+1, y+TILE_HEIGHT-4, 3.0f, 3.0f);
		}
		if(weapon.isHighQuality()) {
			glColor3fv(DEBUG_HIGH_QUALITY_COLOR);
			renderQuad(x+TILE_WIDTH/2-2, y+TILE_HEIGHT-4, 3.0f, 3.0f);
		}
		glColor3fv(DEFAULT_COLOR);
	}
}
void Renderer::render(const RangedWeapon& weapon, float x, float y) {
	renderTexture(m_textureManager->getObjectTexture(TH_RANGED_WEAPON_TYPE, weapon.getType(TH_RANGED_WEAPON_TYPE)), x, y);
	if(DEBUG) {
		if(weapon.getPrefix() != RWP_NONE) {
			glColor3fv(DEBUG_PREFIX_COLOR);
			renderQuad(x+1, y+TILE_HEIGHT-4, 3.0f, 3.0f);
		}
		if(weapon.getSuffix() != RWS_OF_NONE) {
			glColor3fv(DEBUG_SUFFIX_COLOR);
			renderQuad(x+1, y+TILE_HEIGHT-4, 3.0f, 3.0f);
		}
		if(weapon.isHighQuality()) {
			glColor3fv(DEBUG_HIGH_QUALITY_COLOR);
			renderQuad(x+TILE_WIDTH/2-2, y+TILE_HEIGHT-4, 3.0f, 3.0f);
		}
		glColor3fv(DEFAULT_COLOR);
	}
}
void Renderer::render(const Scroll& scroll, float x, float y) {
	renderTexture(m_textureManager->getObjectTexture(TH_SCROLL_TYPE, scroll.getScrambledType()), x, y);
}
void Renderer::render(const Npc& npc, float x, float y) {
	if(!npc.hasStatusEffect(SE_INVIS)) {
		renderTexture(m_textureManager->getObjectTexture(TH_NPC_TYPE, npc.getType(TH_NPC_TYPE)), x, y);
	}
	int offset = (TILE_WIDTH - HEALTH_BAR_LENGTH) / 2;
	float percent = 0;
	switch(npc.getHealthStatus()) {
	case HS_NEAR_DEATH:
		glColor3fv(NEAR_DEATH_COLOR);
		percent = 0.10f;
		break;
	case HS_HEAVILY_WOUNDED:
		glColor3fv(HEAVILY_WOUNDED_COLOR);
		percent = 0.30f;
		break;
	case HS_MODERATELY_WOUNDED:
		glColor3fv(MODERATELY_WOUNDED_COLOR);
		percent = 0.60f;
		break;
	case HS_SLIGHTLY_WOUNDED:
		glColor3fv(SLIGHTLY_WOUNDED_COLOR);
		percent = 0.85f;
		break;
	case HS_NOT_WOUNDED:
		glColor3fv(NOT_WOUNDED_COLOR);
		percent = 1.00f;
		break;
	}
	float middle = (TILE_WIDTH - offset*2) * percent + offset;
	renderQuad(x+offset, y, middle, 2.0f);
	glColor3fv(NPC_WOUNDED_COLOR);
	if(percent < 1.0f) {
		renderQuad(x+middle, y, TILE_WIDTH-offset, 2.0f);
	}
	if(DEBUG) {
		if(npc.hasStatusEffect(SE_POISON)) {
			glColor3fv(DEBUG_POISON_COLOR);
			renderQuad(x+TILE_WIDTH/2, y+TILE_HEIGHT/2, 3.0f, 3.0f);
		}
		glColor3fv(DEFAULT_COLOR);
	}
	glColor3fv(DEFAULT_COLOR);
}
void Renderer::render(const Player& player, float x, float y) {
	if(!player.hasStatusEffect(SE_INVIS)) {
		renderTexture(m_textureManager->getObjectTexture(TH_PLAYER_TYPE, player.getType(TH_PLAYER_TYPE)), x, y);
	}
	int offset = (TILE_WIDTH - HEALTH_BAR_LENGTH) / 2;
	float percent = player.getHealthPercent();
	int middle = (TILE_WIDTH - offset*2) * percent + offset;
	if(percent >= 0.50f) {
		glColor3f(Util::normalize((1.0f-percent)*2.0f), 1.0f, 0.0f);
	} else {
		glColor3f(1.0f, Util::normalize(percent*2.0f), 0.0f);
	}
	glBegin(GL_QUADS);
	renderQuad(x+offset, y, middle, 2.0f);
	glColor3fv(PLAYER_WOUNDED_COLOR);
	if(percent < 1.0f) {
		renderQuad(x+middle, y, TILE_WIDTH-offset, 2.0f);
	}
	glEnd();
	glColor3fv(DEFAULT_COLOR);
}
void Renderer::render(const Door& door, float x, float y) {
	renderTexture(m_textureManager->getObjectTexture(TH_GENERIC_TYPE, GT_OB_DOOR, door.isOpen() ? 0 : 1), x, y);
}
void Renderer::render(const ItemContainer& itemcontainer, float x, float y) {
	renderTexture(m_textureManager->getObjectTexture(TH_ITEMCONTAINER_TYPE, itemcontainer.getType(TH_ITEMCONTAINER_TYPE)), x, y);
	if(DEBUG) {
		glColor3fv(DEBUG_ITEM_CONTAINER_COLOR);
		glRasterPos2f(x+(float(TILE_WIDTH)*0.75f), y+(float(TILE_HEIGHT)*0.75f));
		if(itemcontainer.getNumItems() == 0) {
			glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, '-');
		} else {
			glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, '+');
		}
		glColor3fv(DEFAULT_COLOR);
	}
}
void Renderer::render(const Resource& resource, float x, float y) {
	renderTexture(m_textureManager->getObjectTexture(TH_RESOURCE_TYPE, resource.getType(TH_RESOURCE_TYPE)), x, y);
}
void Renderer::render(const Trap& trap, float x, float y) {
	if(trap.isVisible())
		renderTexture(m_textureManager->getObjectTexture(TH_TRAP_TYPE, trap.getType(TH_TRAP_TYPE)), x, y);
	else if(DEBUG) {
		glColor3fv(DEBUG_HIDDEN_TRAP_COLOR);
		renderQuad(x+1, y+1, 3.0f, 3.0f);
		glColor3fv(DEFAULT_COLOR);
	}
}
void Renderer::render(const Wall& wall, float x, float y) {
	renderTexture(m_textureManager->getWallTexture(wall.getTile()->getLevel()->getDungeon()->getDungeonType(), int(wall.getTile()->getX()), int(wall.getTile()->getY())), x, y);
}
void Renderer::render(const Portal& portal, float x, float y) {
	renderTexture(m_textureManager->getObjectTexture(TH_GENERIC_TYPE, GT_OB_PORTAL, portal.isUp() ? 0 : 1), x, y);
}
void Renderer::render(const Level& level, float x, float y, float width, float height) {
	float playerX = g_player->getTile()->getX();
	float playerY = g_player->getTile()->getY();
	int numTilesVisibleX = width / TILE_WIDTH;
	int numTilesVisibleY = height / TILE_HEIGHT;
	for(int sy = std::max(0.0f, playerY - (numTilesVisibleY / 2)); sy < level.getRows() && sy < playerY + (numTilesVisibleY / 2); sy++) {
		for(int sx = std::max(0.0f, playerX - (numTilesVisibleX / 2)); sx < level.getCols() && sx < playerX + (numTilesVisibleX / 2); sx++) {
			render(*(level.getTile(sx, sy)), x+sx*TILE_WIDTH - (playerX-numTilesVisibleX/2)*TILE_WIDTH, sy*TILE_HEIGHT-y-(playerY-numTilesVisibleY/2)*TILE_HEIGHT + (g_options.o_height-height));
		}
	}
	Tile* selectedTile = g_keyboard->getSelectedTile();
	if(selectedTile != NULL) {
		if(g_gameMode.top() == GM_RANGED_TARGET) {
			if(selectedTile != g_player->getTile()) {
				//std::vector<int>* line = Util::bresenham(g_player->getTile()->getX(), g_player->getTile()->getY(), selectedTile->getX(), selectedTile->getY());
				float h = selectedTile->getY() - g_player->getTile()->getY();
				float w = selectedTile->getX() - g_player->getTile()->getX();
				float angle = atan(abs(h)/abs(w)) * 180.0f / PI;
				if(w < 0 && h >= 0)
					angle = 180 - angle;
				else if(w <= 0 && h <= 0)
					angle = 180 + angle;
				else if(w >= 0 && h < 0)
					angle = 360 - angle;
				float tempX = cos((float)angle*0.01745f);
				float tempY = sin((float)angle*0.01745f);
				float ox = g_player->getTile()->getX()+0.5f;
				float oy = g_player->getTile()->getY()+0.5f;
				Tile* tile = NULL;
				for(int j = 0; tile != selectedTile; j++) {
					tile = level.getTile((int)ox, (int)oy);
					//if(tile->getObstacle() != NULL && !tile->getObstacle()->canSeeThrough())
					if(tile->isVisible()) {
						if(tile->getCharacter() != NULL && tile->getCharacter()->getType(TH_GENERIC_TYPE) != GT_CH_PLAYER)
							glColor4fv(TARGET_GOOD_COLOR);
						else if(tile->getObstacle() != NULL && tile->getObstacle()->isBlocking())
							glColor4fv(TARGET_BAD_COLOR);
						else
							glColor4fv(TARGET_COLOR);
						renderQuad(tile->getX()*TILE_WIDTH - (playerX-numTilesVisibleX/2)*TILE_WIDTH, tile->getY()*TILE_HEIGHT-y-(playerY-numTilesVisibleY/2)*TILE_HEIGHT + (g_options.o_height-height));
						glColor3fv(DEFAULT_COLOR);
					} else {
						break;
					}
					ox += tempX;
					oy += tempY;
				};
				/*for(int i = 2; i < int(line->size())-2; i+=2) {
					Tile* tile = level.getTile(line->at(i), line->at(i+1));
					if(tile->isVisible()) {
						if(tile->getCharacter() != NULL && tile->getCharacter()->getType(TH_GENERIC_TYPE) != GT_CH_PLAYER)
							glColor4fv(TARGET_GOOD_COLOR);
						else if(tile->getObstacle() != NULL && tile->getObstacle()->isBlocking())
							glColor4fv(TARGET_BAD_COLOR);
						else
							glColor4fv(TARGET_COLOR);
						renderQuad(line->at(i)*TILE_WIDTH - (playerX-numTilesVisibleX/2)*TILE_WIDTH, line->at(i+1)*TILE_HEIGHT-y-(playerY-numTilesVisibleY/2)*TILE_HEIGHT + (g_options.o_height-height));
						glColor3fv(DEFAULT_COLOR);
					} else {
						break;
					}
				}*/
				//delete line;
			}
			if(!selectedTile->isVisible())
				glColor4fv(TARGET_BAD_COLOR);
			else if(selectedTile->getCharacter() != NULL && selectedTile->getCharacter()->getType(TH_GENERIC_TYPE) != GT_CH_PLAYER)
				glColor4fv(TARGET_GOOD_COLOR);
			else
				glColor4fv(TARGET_COLOR);
			glColor4fv(TARGET_COLOR);
			renderOutline(selectedTile->getX()*TILE_WIDTH - (playerX-numTilesVisibleX/2)*TILE_WIDTH, selectedTile->getY()*TILE_HEIGHT-y-(playerY-numTilesVisibleY/2)*TILE_HEIGHT + (g_options.o_height-height), 2);
			glColor3fv(DEFAULT_COLOR);
		} else {
			glColor3fv(TILE_HIGHLIGHT_COLOR);
			renderOutline(selectedTile->getX()*TILE_WIDTH - (playerX-numTilesVisibleX/2)*TILE_WIDTH, selectedTile->getY()*TILE_HEIGHT-y-(playerY-numTilesVisibleY/2)*TILE_HEIGHT + (g_options.o_height-height), 2);
			glColor3fv(DEFAULT_COLOR);
		}
	}
}

void Renderer::render(const TextLog& log, float x, float y, float width, float height) {
	std::list<std::string>::const_iterator iter = log.getLine(log.getCurrentLine());
	glColor3fv(TEXT_COLOR);
	y = (log.bottomToTop() ? 4 : height-g_options.o_fontSize) + (g_options.o_height - y - height);
	void* font = getFont();
	for(int i = 0; i < height / (g_options.o_fontSize + 1) && log.getCurrentLine()+i < log.getNumLines(); i++, iter++) {
		renderString(font, *iter, x, y, x+width);
		if(log.bottomToTop())
			y += g_options.o_fontSize + 1;
		else
			y -= g_options.o_fontSize + 1;
	}
	glColor3fv(DEFAULT_COLOR);
}

void* Renderer::getFont() {
	if(g_options.o_fontSize == 12)
		return GLUT_BITMAP_HELVETICA_12;
	else if(g_options.o_fontSize == 18)
		return GLUT_BITMAP_HELVETICA_18;
	else if(g_options.o_fontSize == 15)
		return GLUT_BITMAP_9_BY_15;
	return GLUT_BITMAP_9_BY_15;
}

float Renderer::renderString(void* font, std::string line, float x, float y, float maxX) {
	bool startColor = false;
	for(unsigned int i = 0; i < line.length(); i++) {
		if(line.at(i) == '\r') {
			i++;
			if(startColor)
				glColor3fv(DEFAULT_COLOR);
			else
				glColor3fv(ITEM_LOG_COLORS[line.at(i)-'0']);
			startColor = !startColor;
			continue;
		}
		int width = glutBitmapWidth(font, line.at(i));
		if(x+width > maxX) return x;
		glRasterPos2f(x, y);
		glutBitmapCharacter(font, line.at(i));
		x += width;
	}
	return x;
}

void Renderer::render(const ItemStack& items, float x, float y, float width, float height) {
	int lineNum = 1, prevType = -1, maxLines = (height-g_options.o_fontSize) / (TILE_HEIGHT+4);
	char letter = 'a';
	std::string letterString;
	renderString(getFont(), items.getTitle(), x+1, g_options.o_height - y - g_options.o_fontSize, x+width);
	std::vector<ItemStackItem*>* itemStackItems = items.getItems();
	for(unsigned int i = items.convertMod(0); i < itemStackItems->size() && lineNum != maxLines+1; i++) {
		if(!itemStackItems->at(i)->filtered && itemStackItems->at(i)->visible && itemStackItems->at(i)->item->getNumStacked() - itemStackItems->at(i)->stackChange > 0) {
			Item* item = itemStackItems->at(i)->item;
			if(item->getType(TH_GENERIC_TYPE) != prevType) {
				prevType = item->getType(TH_GENERIC_TYPE);
				glColor3fv(ITEM_STACK_HEADER_COLOR);
				renderString(getFont(), std::string(g_stringLib->getMiscString(MST_FILTER, ItemStack::filterMap[GenericType(prevType)], 0, true) + " (" + (ItemStack::filterChars[ItemStack::filterMap[GenericType(prevType)]]) + ")"),
						x+1, g_options.o_height - y - (TILE_HEIGHT+4) * lineNum++ - g_options.o_fontSize + 5, x+width);
				glColor3fv(DEFAULT_COLOR);
				if(lineNum == maxLines+1) break;
			}
			if(letter == 'z'+1) letter = 'A';
			int mod = Util::letterMod(letter);
			letterString = letter++;
			item->render(x+5, g_options.o_height - y - lineNum*(TILE_HEIGHT+4) - g_options.o_fontSize);
			renderString(getFont(), std::string(item->isEquipped() ? "*" : "") + letterString + " " + (itemStackItems->at(i)->selected ? "+" : "-") + " " + item->getColoredItemName(itemStackItems->at(i)->stackChange), x+7+TILE_WIDTH,
				g_options.o_height - y - lineNum++*(TILE_HEIGHT+4)+(TILE_HEIGHT - g_options.o_fontSize)/2 - g_options.o_fontSize, x+width);
			glColor3fv(DEFAULT_COLOR);
		}
	}
}

void Renderer::render(const Equipment& equipment, float x, float y, float width, float height) {
	void* font = getFont();
	float tempX;
	y = g_options.o_height - y - (TILE_HEIGHT+2);
	std::string letter = "a";
	for(EquipmentLocation i = EL_LEFT_HAND; i < NUM_EQUIPMENT_LOCATIONS; i = EquipmentLocation(int(i)+1)) {
		tempX = renderString(font, letter + " - " + g_stringLib->getMiscString(MST_EQUIPMENT, i) + ": ", x, y, width);
		Item* item = equipment.get(i);
		if(item == NULL) {
			renderString(font, "(None)", tempX, y, width-tempX);
		} else {
			item->render(tempX, y);
			tempX += TILE_WIDTH;
			renderString(font, " " + item->getColoredName(), tempX, y, width-tempX);
		}
		y -= TILE_HEIGHT+4;
		letter[0]++;
	}
}

void Renderer::renderPlayerInfo(const Player& player, float x, float y, float width, float height) {
	int lineNum = 1;
	void* font = getFont();
	float percent = player.getHealthPercent();
	glColor3fv(PLAYER_INFO_NAME_COLOR);
	renderString(font, player.getName(), x+1, g_options.o_height-y-g_options.o_fontSize*lineNum++, x+width);

	glColor3fv(PLAYER_INFO_CATEGORY_COLOR);
	int tempX = renderString(font, "Health: ", x+1, g_options.o_height-y-g_options.o_fontSize*lineNum, x+width/2);
	if(percent >= 0.50f) {
		glColor3f(Util::normalize((1.0f-percent)*2.0f), 1.0f, 0.0f);
	} else {
		glColor3f(1.0f, Util::normalize(percent*2.0f), 0.0f);
	}
	tempX = renderString(font, Util::intToString(player.getCurrentHealth()), tempX, g_options.o_height-y-g_options.o_fontSize*lineNum, x+width);
	glColor3fv(PLAYER_INFO_CATEGORY_COLOR);
	tempX = renderString(font, "/", tempX, g_options.o_height-y-g_options.o_fontSize*lineNum, x+width);
	glColor3fv(TEXT_COLOR);
	renderString(font, Util::intToString(player.getMaxHealth()) + " ", tempX, g_options.o_height-y-g_options.o_fontSize*lineNum++, x+width);

	for(int i = STR; i < NUM_STATS; i++) {
		glColor3fv(PLAYER_INFO_CATEGORY_COLOR);
		tempX = renderString(font, g_stringLib->getMiscString(MST_STAT, Stat(i), 1) + ": ", (i%2==0 ? x+1 : x+width/2+1), g_options.o_height-y-g_options.o_fontSize*(lineNum), (i%2==0 ? x+width/2 : x+width));
		glColor3fv(PLAYER_INFO_STAT_COLOR);
		renderString(font, Util::intToString(player.getStat(Stat(i))), tempX, g_options.o_height-y-g_options.o_fontSize*(i%2 == 0 ? lineNum : lineNum++), (i%2==0 ? x+width/2 : x+width));
	}
	if(NUM_STATS % 2 == 1)
		lineNum++;
	glColor3fv(PLAYER_INFO_CATEGORY_COLOR);
	tempX = renderString(font, "Dodge: ", x+1, g_options.o_height-y-g_options.o_fontSize*lineNum, x+width/2);
	glColor3fv(TEXT_COLOR);
	tempX = renderString(font, Util::intToString(player.getDodgeBonus()), tempX, g_options.o_height-y-g_options.o_fontSize*lineNum, x+width);
	glColor3fv(PLAYER_INFO_CATEGORY_COLOR);
	tempX = renderString(font, "Armor: ", x+width/2+1, g_options.o_height-y-g_options.o_fontSize*lineNum, x+width);
	glColor3fv(TEXT_COLOR);
	tempX = renderString(font, Util::intToString(player.getArmorBonus()), tempX, g_options.o_height-y-g_options.o_fontSize*lineNum++, x+width);
	glColor3fv(PLAYER_INFO_CATEGORY_COLOR);
	tempX = renderString(font, "Block: ", x+1, g_options.o_height-y-g_options.o_fontSize*lineNum, x+width);
	glColor3fv(TEXT_COLOR);
	tempX = renderString(font, Util::intToString(player.getBlock()), tempX, g_options.o_height-y-g_options.o_fontSize*lineNum++, x+width);
	glColor3fv(PLAYER_INFO_CATEGORY_COLOR);
	tempX = renderString(font, "Location: ", x+1, g_options.o_height-y-g_options.o_fontSize*lineNum, x+width);
	glColor3fv(TEXT_COLOR);
	renderString(font, g_stringLib->getMiscString(MST_DUNGEON, player.getTile()->getLevel()->getDungeon()->getDungeonType(), 1) + Util::intToString(player.getTile()->getLevel()->getLevelNum()+1),
			tempX, g_options.o_height-y-g_options.o_fontSize*lineNum++, x+width);
	glColor3fv(PLAYER_INFO_CATEGORY_COLOR);
	tempX = renderString(font, "Level: ", x+1, g_options.o_height-y-g_options.o_fontSize*lineNum, x+width);
	glColor3fv(TEXT_COLOR);
	tempX = renderString(font, Util::intToString(player.getLevel()), tempX, g_options.o_height-y-g_options.o_fontSize*lineNum++, x+width);
	glColor3fv(PLAYER_INFO_CATEGORY_COLOR);
	tempX = renderString(font, "Exp/Next: ", x+1, g_options.o_height-y-g_options.o_fontSize*lineNum, x+width);
	glColor3fv(TEXT_COLOR);
	tempX = renderString(font, Util::intToString(player.getExperience()), tempX, g_options.o_height-y-g_options.o_fontSize*lineNum, x+width);
	glColor3fv(PLAYER_INFO_CATEGORY_COLOR);
	tempX = renderString(font, "/", tempX, g_options.o_height-y-g_options.o_fontSize*lineNum, x+width);
	glColor3fv(TEXT_COLOR);
	tempX = renderString(font, Util::intToString(player.getNextLevelExperience()), tempX, g_options.o_height-y-g_options.o_fontSize*lineNum++, x+width);
	glColor3fv(PLAYER_INFO_CATEGORY_COLOR);
	tempX = renderString(font, g_stringLib->getMiscString(MST_EQUIPMENT, EL_LEFT_HAND, 1) + ": ", x+1, g_options.o_height-y-g_options.o_fontSize*lineNum, x+width);
	glColor3fv(TEXT_COLOR);
	Item* leftHand = player.getEquipment()->get(EL_LEFT_HAND);
	renderString(font, leftHand ? leftHand->getColoredName() : "(none)", tempX, g_options.o_height-y-g_options.o_fontSize*lineNum++, x+width);
	glColor3fv(PLAYER_INFO_CATEGORY_COLOR);
	tempX = renderString(font, g_stringLib->getMiscString(MST_EQUIPMENT, EL_RIGHT_HAND, 1) + ": ", x+1, g_options.o_height-y-g_options.o_fontSize*lineNum, x+width);
	glColor3fv(TEXT_COLOR);
	Item* rightHand = player.getEquipment()->get(EL_RIGHT_HAND);
	renderString(font, rightHand ? rightHand->getColoredName() : "(none)", tempX, g_options.o_height-y-g_options.o_fontSize*lineNum++, x+width);

	switch(player.getSatiationStatus()) {
	case SS_STARVING:
		glColor3fv(PLAYER_INFO_STARVING_COLOR);
		break;
	case SS_VERY_HUNGRY:
	case SS_HUNGRY:
		glColor3fv(PLAYER_INFO_HUNGRY_COLOR);
		break;
	case SS_FULL:
	case SS_VERY_FULL:
	case SS_BLOATED:
		glColor3fv(PLAYER_INFO_FULL_COLOR);
		break;
	}
	renderString(font, g_stringLib->getMiscString(MST_SATIATION, player.getSatiationStatus()), x+1, g_options.o_height-y-g_options.o_fontSize*lineNum++, x+width);
	lineNum++;

	for(StatusEffect i = SE_POISON; i < NUM_STATUS_EFFECTS; i = StatusEffect(int(i+1))) {
		int power;
		if(power = player.hasStatusEffect(i)) {
			glColor3fv(PLAYER_INFO_GOOD_STATUS_COLOR);
			switch(i) {
			case SE_INVIS:
				if(power < 3)
					glColor3fv(PLAYER_INFO_GOOD_STATUS_FADING_COLOR);
				break;
			case SE_POISON:
				if(power < 200)
					glColor3fv(PLAYER_INFO_BAD_STATUS_COLOR);
				else if(power < 400)
					glColor3fv(PLAYER_INFO_BAD_STATUS_MEDIUM_COLOR);
				else
					glColor3fv(PLAYER_INFO_BAD_STATUS_STRONG_COLOR);
				break;
			}
			renderString(font, g_stringLib->getMiscString(MST_STATUS_EFFECT, i, 1, true), x+1, g_options.o_height-y-g_options.o_fontSize*lineNum++, x+width);
		}
	}

	glColor3fv(DEFAULT_COLOR);
}

void Renderer::render(const RecipeManager& recipeManager, float x, float y, float width, float height) {
	int modX = x;
	std::string letter;
	for(int i = 0; i < NUM_RECIPE_TYPES; i++) {
		glColor3fv(TEXT_COLOR);
		letter = 'a'+i;
		modX = renderString(getFont(), letter + " - ", x+1, g_options.o_height - y - g_options.o_fontSize * (i+1), x+width/2);
		if(recipeManager.getRecipe(i)->canCraft(g_player)) {
			glColor3fv(RECIPE_CAN_CRAFT_COLOR);
		} else {
			glColor3fv(RECIPE_CAN_NOT_CRAFT_COLOR);
		}
		renderString(getFont(), g_stringLib->getMiscString(MST_RECIPE, RecipeType(i)), modX, g_options.o_height - y - g_options.o_fontSize * (i+1), x+width/2);
	}
	glColor3fv(DEFAULT_COLOR);
}

void Renderer::render(const Recipe& recipe, float x, float y, float width, float height) {
	int lineNum = 1;
	if(recipe.canCraft(g_player)) {
		glColor3fv(RECIPE_CAN_CRAFT_COLOR);
	} else {
		glColor3fv(RECIPE_CAN_NOT_CRAFT_COLOR);
	}
	renderString(getFont(), g_stringLib->getMiscString(MST_RECIPE, recipe.getRecipeType()), x+1, g_options.o_height - y - g_options.o_fontSize * lineNum++, x+width);
	lineNum++;
	std::list<RecipeItem*>* recipeItems = recipe.getRecipe();
	int modX = x;
	for(std::list<RecipeItem*>::const_iterator iter = recipeItems->begin(); iter != recipeItems->end(); iter++) {
		if(g_player->inventoryContains((*iter)->typeCategory, (*iter)->type, (*iter)->numRequired)) {
			glColor3fv(RECIPE_CAN_CRAFT_COLOR);
		} else {
			glColor3fv(RECIPE_CAN_NOT_CRAFT_COLOR);
		}
		renderString(getFont(), g_stringLib->getTextString(ST_CRAFT_ITEM_DETAILS, (*iter)->name.c_str(), g_stringLib->getObjectString((*iter)->typeCategory, (*iter)->type).c_str(), Util::intToString((*iter)->numRequired).c_str(),
			((*iter)->required ? "" : "(optional)")), x+1, g_options.o_height - y - g_options.o_fontSize * lineNum++, x+width);
	}
	lineNum++;
	glColor3fv(TEXT_COLOR);
	renderString(getFont(), g_stringLib->getTextString(ST_CRAFT_INSTRUCTIONS), x+1, g_options.o_height - y - g_options.o_fontSize * lineNum++, x+width);
	glColor3fv(DEFAULT_COLOR);
}

void Renderer::render(const AvailableTalents& talents, float x, float y, float width, float height) {
	std::vector<Talent>* t = talents.getTalents();
	std::string letter;
	glColor3fv(TEXT_COLOR);
	renderString(getFont(), g_stringLib->getTextString(ST_INPUT_TALENT), x+1, g_options.o_height - y - g_options.o_fontSize, x+width);
	for(unsigned int i = 0; i < t->size(); i++) {
		letter = 'a'+i;
		renderString(getFont(), letter + " - " + g_stringLib->getMiscString(MST_TALENT, t->at(i), 0, true) + ": " + g_stringLib->getMiscString(MST_TALENT, t->at(i), 1), x+1, g_options.o_height - y - g_options.o_fontSize * (i+2), x+width);
	}
	glColor3fv(DEFAULT_COLOR);
}

void Renderer::renderSelectSkill(const std::map<Skill, float>& skills, float x, float y, float width, float height) {
	std::string letter;
	glColor3fv(TEXT_COLOR);
	renderString(getFont(), g_stringLib->getTextString(ST_INPUT_SKILL), x+1, g_options.o_height - y - g_options.o_fontSize, x+width);
	int counter = 0;
	for(int i = 0; i < NUM_SKILLS; i++) {
		Skill skill = Skill(i);
		if(g_player->hasSkill(skill)) {
			int tempX = x+1;
			if(g_player->getSkillLevel(skill) < 10) {
				glColor3fv(TEXT_COLOR);
				letter = 'a'+counter++;
				tempX = renderString(getFont(), letter + " - ", tempX, g_options.o_height - y - g_options.o_fontSize * (counter+1), x+width);
			} else {
				glColor3fv(DARKGRAY);
			}
			renderString(getFont(), g_stringLib->getMiscString(MST_SKILL, skill, 0, true) + ": " + Util::floatToString(skills.at(skill)), tempX, g_options.o_height - y - g_options.o_fontSize * (counter+1), x+width);
		}
	}
	glColor3fv(DEFAULT_COLOR);
}

void Renderer::renderSelectNewSkill(const std::map<Skill, float>& skills, float x, float y, float width, float height) {
	std::string letter;
	glColor3fv(TEXT_COLOR);
	renderString(getFont(), g_stringLib->getTextString(ST_INPUT_NEW_SKILL), x+1, g_options.o_height - y - g_options.o_fontSize, x+width);
	int counter = 0;
	for(int i = 0; i < NUM_SKILLS; i++) {
		Skill skill = Skill(i);
		if(!g_player->hasSkill(skill)) {
			letter = 'a'+counter++;
			renderString(getFont(), letter + " - " + g_stringLib->getMiscString(MST_SKILL, skill, 0, true) + ": " + g_stringLib->getMiscString(MST_SKILL, skill, 1), x+1, g_options.o_height - y - g_options.o_fontSize * (counter+1), x+width);
		}
	}
	glColor3fv(DEFAULT_COLOR);
}

void Renderer::renderTitle(float x, float y, float width, float height) {
	glColor3fv(TEXT_COLOR);
	renderTexture(m_textureManager->getTexture(0), x+50, g_options.o_height-y-150, 400, 100);
	renderString(getFont(), "(n) - New Game", (x+width)/4, (g_options.o_height-y)*3/4, x+width);
	renderString(getFont(), "(l) - Load Game", (x+width)/4, (g_options.o_height-y)*3/4-(g_options.o_fontSize+1), x+width);
	renderString(getFont(), "(q) - Quit", (x+width)/4, (g_options.o_height-y)*3/4-2*(g_options.o_fontSize+1), x+width);
	glColor3fv(DEFAULT_COLOR);
}

void Renderer::renderLoad(const std::vector<std::string>& loadGames, float x, float y, float width, float height) {
	std::string letter;
	glColor3fv(TEXT_COLOR);
	int counter = 0;
	for(int i = 0; i < int(loadGames.size()); i++) {
		letter = 'a'+counter++;
		renderString(getFont(), "(" + letter + ") - " + loadGames[i], x+1, g_options.o_height - y - g_options.o_fontSize * (counter+1), x+width);
	}
	glColor3fv(DEFAULT_COLOR);
}
